package org.example.expansionpoint.applicationContextAware;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;

/**
 * @Description:
 */

@SpringBootApplication
public class TestApplicationContextAware {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(TestApplicationContextAware.class, args);

        context.close();
    }

    /**
     * <p>
     * 类似的接口还有：
     * <ul>
     *     <li>EnvironmentAware</li>
     *     <li>EmbeddedValueResolverAware</li>
     *     <li>ResourceLoaderAware</li>
     *     <li>ApplicationEventPublisherAware</li>
     *     <li>MessageSourceAware</li>
     *     <li>ApplicationStartupAware</li>
     * </ul>
     * </p>
     */
    @Component
    static class MyApplicationContextAware implements ApplicationContextAware {
        private ApplicationContext applicationContext;

        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
            System.out.println("2. Spring 上下文 ApplicationContext 被注入");
        }

        public ApplicationContext getApplicationContext() {
            return applicationContext;
        }

        public Object getBean(String name) {
            return getApplicationContext().getBean(name);
        }

        public <T> T getBean(Class clazz) {
            return (T) getApplicationContext().getBean(clazz);
        }

        public <T> T getBean(String name, Class clazz) {
            return (T) getApplicationContext().getBean(name, clazz);
        }
    }

    @Component
    static class MyApplicationContext {

        private ApplicationContext applicationContext;

        @Autowired
        public void setApplicationContext(ApplicationContext applicationContext) {
            this.applicationContext = applicationContext;
            System.out.println("1. 使用 @Autowired 注入 ApplicationContext");
        }
    }

    @Component
    static class MyFirstBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

        @Autowired
        private ApplicationContext context;

        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            System.out.println("依赖注入的 ApplicationContext 为" + context);
        }
    }

    @Component
    static class MySecondBeanFactoryPostProcessor implements BeanFactoryPostProcessor, ApplicationContextAware {

        private ApplicationContext context;

        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            System.out.println("使用 ApplicationContextAware 注入的 ApplicationContext 为" + context);
        }

        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.context = applicationContext;
        }
    }
}
